<?php
/**
 * Created by PhpStorm.
 * User: ysk
 * Date: 2021/6/18
 * Time: 15:27
 */
namespace api\base;

use Yii;
use yii\base\InlineAction;
use yii\web\Response;
use yii\filters\Cors;
use yii\web\BadRequestHttpException;
use  yii\web\Controller;


class BaseApiController extends Controller {


    public $enableCsrfValidation = false;

    public static $corsFilterSetting = [
        'class' => Cors::class,
        'cors'  => [
            'Origin'                           => ['*'],
            'Access-Control-Request-Method'    => ['GET', 'POST', 'PUT'],
            'Access-Control-Request-Headers'   => ['*'],
            'Access-Control-Allow-Credentials' => false,
        ],
    ];

    public function init()
    {
        parent::init();
    }

    /**
     * @return array
     */
    public function behaviors()
    {
        $behaviors = parent::behaviors();
        // $behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_HTML;
        unset($behaviors['contentNegotiator']['formats']['application/xml']);

        // 关闭跨域限制
        $behaviors['corsFilter'] = self::$corsFilterSetting;

        return $behaviors;
    }

    /**
     * Binds the parameters to the action.
     * This method is invoked by [[\yii\base\Action]] when it begins to run with the given parameters.
     * This method will check the parameter names that the action requires and return
     * the provided parameters according to the requirement. If there is any missing parameter,
     * an exception will be thrown.
     *
     * @param \yii\base\Action $action the action to be bound with parameters
     * @param array            $params the parameters to be bound to the action
     *
     * @return array the valid parameters that the action can run with.
     * @throws ReflectionException
     * @throws InvalidConfigException
     * @throws ApiException
     */
    public function bindActionParams($action, $params)
    {
        Yii::beginProfile('BaseApiController->bindActionParams');
        if ($action instanceof InlineAction) {
            $method = new \ReflectionMethod($this, $action->actionMethod);
        } else {
            $method = new \ReflectionMethod($action, 'run');
        }

        $args         = [];
        $missing      = [];
        $actionParams = [];

        $bodyParams = Yii::$app->request->getBodyParams();
        foreach ($method->getParameters() as $param) {
            $name  = $param->getName(); //params
            $clazz = $param->getClass();
            if (!empty($clazz)) {
                if ($clazz->isSubclassOf(BaseApiParams::className())) {
                    // 组装
                    $paramObj = $clazz->newInstance();
                    if ($paramObj instanceof BaseApiParams) {
                        // 先取get,再取post
                        // $paramObj->load(ArrayHelper::merge($params, $bodyParams));
                        // 只取post 请求体中的参数

                            if (isset($bodyParams['page_type']) && $paramObj->hasProperty('page_type')) {
                                $paramObj->page_type = $bodyParams['page_type'];
                            }
                            $paramObj->load($bodyParams);

                        $args[] = $actionParams[$name] = $paramObj;
                        continue;
                    }
                }
            }

            if (array_key_exists($name, $bodyParams)) {

                if ($param->isArray()) {
                    $args[] = $actionParams[$name] = (array)$bodyParams[$name];
                } elseif (!is_array($bodyParams[$name])) {
                    $args[] = $actionParams[$name] = $bodyParams[$name];
                }
                unset($params[$name]);

            } elseif (array_key_exists($name, $params)) {
                if ($param->isArray()) {
                    $args[] = $actionParams[$name] = (array)$params[$name];
                } elseif (!is_array($params[$name])) {
                    $args[] = $actionParams[$name] = $params[$name];
                }
                unset($params[$name]);

            } elseif ($param->isDefaultValueAvailable()) {
                $args[] = $actionParams[$name] = $param->getDefaultValue();
            } else {
                $missing[] = $name;
            }
        }

        Yii::endProfile('BaseApiController->bindActionParams');

        if (!empty($missing)) {
            throw new BadRequestHttpException(Yii::t('yii', 'Missing required parameters: {params}',
                ['params' => implode(', ', $missing),]));
        }

        $this->actionParams = $actionParams;
        return $args;
    }


    /**
     * @param string $id
     * @param array  $params
     *
     * @return mixed|null
     * @throws \Exception
     * @throws \Throwable
     */
    public function runAction($id, $params = [])
    {
        $result = null;
        $err    = null;

        $GLOBALS['ApiBusiStartTime'] = $runStartTs = microtime(true);

        Yii::beginProfile($id, __METHOD__);

        $result = parent::runAction($id, $params);
        if ($result instanceof ResponseApi) {
            Yii::$app->response->format = Response::FORMAT_JSON;
        }

        Yii::endProfile($id, __METHOD__);

        $GLOBALS['ApiBusiStopTime'] = $runStopTs = microtime(true);
        $GLOBALS['ApiBusiRunTime']  = $busiRunTime = $runStopTs - $runStartTs;


        return $result;
    }

}
